/*
* Copyright 2010 Pavel Kozhin 
*
* Licensed under the Apache License, Version 2.0 (the "License"); 
* you may not use this file except in compliance with the License. 
* You may obtain a copy of the License at 
* 
* http://www.apache.org/licenses/LICENSE-2.0
* 
* Unless required by applicable law or agreed to in writing, software 
* distributed  under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
* See the License for the specific language governing permissions and 
* limitations under the License.
*
* Author: Pavel Kozhin.
*/

package org.etherframework.wire.wirings
{
	import flash.events.IEventDispatcher;
	import flash.utils.Dictionary;
	
	import org.etherframework.core.Access;
	import org.etherframework.core.DomainAccess;
	import org.etherframework.core.IBridge;
	import org.etherframework.reflection.Accessor;
	import org.etherframework.reflection.Metadata;
	import org.etherframework.reflection.MetadataMember;
	import org.etherframework.reflection.Variable;
	import org.etherframework.wire.WiringData;
	import org.etherframework.wire.WiringUtil;

	public final class Dispatcher implements IWiring, IInjection
	{
		[Inspectable(defaultValue="local", enumeration="local,hierarchical,@hierarchical,hierarchical@,global")]
		public var access:String = "local";
		
		[Inspectable(defaultValue="single", enumeration="single,multiple")]
		public var domain:String = "single";
		
		public var member:Object;
		
		private var bridge:IBridge;
		
		private var dictionary:Dictionary;
		
		public function wire(name:String, target:Object, item:Object, data:WiringData):Boolean
		{
			if (!((item is Variable) || (item is Accessor)))
				return false;
			
			var member:MetadataMember = item as MetadataMember;
			var metadatas:Array;
			var metadatasLen:int;
			var metadata:Metadata;
			var properties:Dictionary;
			var dispatcher:IEventDispatcher;
			
			dictionary = new Dictionary(true);
			metadatas = member.metadata;
			metadatasLen = metadatas.length;
			this.member = (member.uri) ? 
					new QName(new Namespace(member.uri), member.name) : member.name;
			bridge = data.bridge;
			
			for (var i:int = 0; i < metadatasLen; ++i)
			{
				metadata = metadatas[i];
				
				if (metadata.name == name)
				{
					dictionary[target] = true;
					properties = WiringUtil.getProperties(metadata.properties);
					access = Access.getAccess(properties["access"]);
					domain = DomainAccess.getAccess(properties["domain"]);
					target[this.member] = new DispatcherFacade(access, domain, bridge, getTarget);
					
					return true;
				}
			}
			
			return false;
		}
		
		public function unwire(target:Object):Boolean
		{
			dictionary = null;
			
			try {
				if (target[member])
				{
					target[member] = null;
					return true;
				}
			} catch (e:*){};
			
			return false;
		}
		
		public function inject(name:String, target:Object, data:WiringData):Boolean
		{
			try {
				if (!target[member])
				{
					access = Access.getAccess(access);
					domain = DomainAccess.getAccess(domain);
					dictionary = new Dictionary(true);
					dictionary[target] = true;
					target[member] = new DispatcherFacade(access, domain, data.bridge, getTarget);
					
					return true;
				}
			} catch (e:*) {}
			
			return false;
		}
		
		private function getTarget():Object
		{
			for (var target:Object in dictionary){}
			return target;
		}
		
	}
}
import flash.events.Event;
import flash.events.IEventDispatcher;
import flash.utils.Dictionary;

import org.etherframework.core.IBridge;
import org.etherframework.wire.WiringUtil;

final class DispatcherFacade implements IEventDispatcher
{
	private var access:String;
	
	private var domain:String;
	
	private var bridge:IBridge;
	
	private var targetClosure:Function;
	
	public function DispatcherFacade(access:String, domain:String, bridge:IBridge, targetClosure:Function)
	{
		this.access = access;
		this.domain = domain;
		this.bridge = bridge;
		this.targetClosure = targetClosure;
	}
	
	public function addEventListener(type:String, listener:Function, 
									 useCapture:Boolean=false, priority:int=0, 
									 useWeakReference:Boolean=false):void
	{
	}
	
	public function removeEventListener(type:String, listener:Function, useCapture:Boolean=false):void
	{
	}
	
	public function dispatchEvent(event:Event):Boolean
	{
		if (!event)
			return false;
		
		if (event.bubbles)
		{
			return bridge.host.dispatchEvent(event);
		}
		
		return bridge.interaction.dispatchEvent(event, targetClosure(), access, domain);
	}
	
	public function hasEventListener(type:String):Boolean
	{
		return false;
	}
	
	public function willTrigger(type:String):Boolean
	{
		return false;
	}

}